-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Raise all SystemCallErrors as Trilogy::Error
#63
Raise all SystemCallErrors as Trilogy::Error
#63
Conversation
bc6c5a4
to
b243b50
Compare
So: Errno.constants.map { |c| Errno.const_get(c) }.select { |c| c.is_a?(Class) && c < SystemCallError }. Is the proper way to do it I think. The only issue is: >> Errno.constants.map { |c| Errno.const_get(c) }.select { |c| c.is_a?(Class) && c < SystemCallError }.size
=> 158 And the vast majority of them will never happen. Alternatively, we can do it manually for a subset of |
b243b50
to
e5a53a5
Compare
I'm not super confident identifying which errnos seem reasonable to care about, so as long as we're sticking to the module-based approach my vote would be to enumerate all of them. If there are more that we truly expect, maybe we should promote them to proper classes? cc @matthewd any opinions here? |
Yeah my concern is that it's really hard to define a list of plausibly-expectable errors (e.g. EHOSTUNREACH probably wouldn't make an initial cut, but considered properly does seem like a thing that an interested caller could reasonably want to specifically handle as a connection issue -> retry / whatever). Not to mention the theoretical variation across platforms once we stray from the basics. My first thought was to use a lazy hash... which doesn't feel like a particularly good idea, and would be messy though maybe not ridiculous. It's a bounded list, and most processes most of the time won't ever see / need most classes. This feels terrible but I can't see an alternative that doesn't pre-encode a subset of errnos that are "allowed" to happen. 😕 |
Oh actually lazy hash sounds like a good idea? e.g. something like this right? class SyscallError
ERRORS = {}
class << self
def from_errno(errno, message)
ERRORS.fetch(errno) do |errno|
errno_name = Errno.constants.find { |c| Errno.const_get(c)::Errno == errno }
errno_subclass = Class.new(Errno.const_get(errno_name)) { include Trilogy::Error }
ERRORS[errno] = const_set(errno_name, errno_subclass)
end.new(message)
end
end
end That way we avoid subclassing the unlikely ones. A bit messy, but not any worse than iterating all of em IMO 😅 |
I'd advise against dynamic It also make it weird because you can't reference the error before it's actually raised. That said, defining the 150-ish classes would use about 30kB, it's a indeed a bit much... but acceptable? >> ObjectSpace.memsize_of(Class.new(StandardError)) * 154
=> 29568 |
Oh good to know, thank you Jean 🙇♀️
I think it would be closer to 20kbB; several of the
|
Fine by me. |
I think @casperisfine was advising against the combo of Failing that, I think we'd want to define both
|
Yeah, if it's eagerly defined it's fine. |
Ahh gotcha, yeah that makes more sense in terms of invalidating the global constant cache. Let me bring back back the const_set then 👍 |
8dc87ad
to
4623eb5
Compare
This allows syscall errors to be rescued generically by Trilogy::Error, or handled individually by consumers using their oriinal Errno classes. To make this work, we subclass all of the SystemCallErrors and include the base error module on each of them. I've also removed the constructors from the existing Errno class subclasses (Trilogy::TimeoutError, Trilogy::ConnectionClosedError, etc.). We never set an error_code on syscall errors, so the constructors are not needed.
4623eb5
to
c104e5c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Background
See #58 for more context.
This allows syscall errors to be rescued generically by
Trilogy::Error
, or handled individually by consumers using their original Errno classes.To make this work, we subclass all of the SystemCallErrors and include the base error module on each of them.
I've also removed the constructors from the existing Errno class subclasses (
Trilogy::TimeoutError
,Trilogy::ConnectionClosedError
, etc.). We never set anerror_code
on syscall errors, so the constructors shouldn't be needed.If anyone has input on a better way to handle including the
Trilogy::Error
module on all of the Errno classes, let me know! Enumerating descendants ofSystemCallError
, subclassing them, and includingTrilogy::Error
seems like the most straightforward approach so far, but is admittedly not pretty.